<script lang="ts" setup>
import { getCurrentInstance, onBeforeMount, onBeforeUnmount, onMounted, ref } from "vue";
import { type RouteRecordName, type RouteRecordRaw } from "vue-router";

interface Props {
  list: RouteRecordRaw[];
  isPressUpOrDown: boolean;
}

/** 选中的菜单 */
const modelValue = defineModel<RouteRecordName | undefined>({ required: true });
const props = defineProps<Props>();

const instance = getCurrentInstance();
const scrollbarHeight = ref<number>(0);

/** 菜单的样式 */
const itemStyle = (item: RouteRecordRaw) => {
  const flag = item.name === modelValue.value;
  return {
    background: flag ? "var(--el-color-primary)" : "",
    color: flag ? "#ffffff" : ""
  };
};

/** 鼠标移入 */
const handleMouseenter = (item: RouteRecordRaw) => {
  // 如果上键或下键与 mouseenter 事件同时生效，则以上下键为准，不执行该函数的赋值逻辑
  if (props.isPressUpOrDown) return;
  modelValue.value = item.name;
};

/** 计算滚动可视区高度 */
const getScrollbarHeight = () => {
  // el-scrollbar max-height="40vh"
  scrollbarHeight.value = Number((window.innerHeight * 0.4).toFixed(1));
};

/** 根据下标计算到顶部的距离 */
const getScrollTop = (index: number) => {
  const currentInstance = instance?.proxy?.$refs[`resultItemRef${index}`] as HTMLDivElement[];
  if (!currentInstance) return 0;
  const currentRef = currentInstance[0];
  const scrollTop = currentRef.offsetTop + 128; // 128 = 两个 result-item （56 + 56 = 112）高度与上下 margin（8 + 8 = 16）大小之和
  return scrollTop > scrollbarHeight.value ? scrollTop - scrollbarHeight.value : 0;
};

/** 在组件挂载前添加窗口大小变化事件监听器 */
onBeforeMount(() => {
  window.addEventListener("resize", getScrollbarHeight);
});

/** 在组件挂载时立即计算滚动可视区高度 */
onMounted(() => {
  getScrollbarHeight();
});

/** 在组件卸载前移除窗口大小变化事件监听器 */
onBeforeUnmount(() => {
  window.removeEventListener("resize", getScrollbarHeight);
});

defineExpose({ getScrollTop });
</script>

<template>
  <!-- 外层 div 不能删除，是用来接收父组件 click 事件的 -->
  <div>
    <div
      v-for="(item, index) in list"
      :key="index"
      :ref="`resultItemRef${index}`"
      class="result-item"
      :style="itemStyle(item)"
      @mouseenter="handleMouseenter(item)"
    >
      <SvgIcon v-if="item.meta?.svgIcon" :name="item.meta.svgIcon" />
      <component v-else-if="item.meta?.elIcon" :is="item.meta.elIcon" class="el-icon" />
      <span class="result-item-title">
        {{ item.meta?.title }}
      </span>
      <SvgIcon v-if="modelValue && modelValue === item.name" name="keyboard-enter" />
    </div>
  </div>
</template>

<style lang="scss" scoped>
.result-item {
  display: flex;
  align-items: center;
  height: 56px;
  padding: 0 15px;
  margin-top: 8px;
  border: 1px solid var(--el-border-color);
  border-radius: 4px;
  cursor: pointer;

  .svg-icon {
    min-width: 1em;
    font-size: 18px;
  }

  .el-icon {
    width: 1em;
    font-size: 18px;
  }

  &-title {
    flex: 1;
    margin-left: 12px;
  }
}
</style>
